package com.demo.redis;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.serializer.GenericToStringSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.Closeable;
import java.util.Map;
import java.util.Set;

@SpringBootTest(classes = DemoRedisApplication.class)
@RunWith(SpringRunner.class)
public class redisCRUD {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void run_list(){
        redisTemplate.setValueSerializer(new GenericToStringSerializer<String>(String.class));
        redisTemplate.delete("list");
        redisTemplate.opsForList().rightPush("list","a");
        redisTemplate.opsForList().rightPush("list","b");
        redisTemplate.opsForList().rightPush("list","c");

        /*System.out.println(redisTemplate.opsForList().size("list"));
        redisTemplate.opsForList().trim("list",0,1);
        System.out.println(redisTemplate.opsForList().range("list",0,2));
        Long size = redisTemplate.opsForList().size("list");
        for (int i = 0; i <size; i++) {
            System.out.println(redisTemplate.opsForList().leftPop("list"));
        }*/

        redisTemplate.opsForList().rightPush("list","d");

        redisTemplate.opsForList().rightPush("list","c","e");


        redisTemplate.opsForList().range("list",0,-1).forEach(s -> {
            System.out.println(s);
        });

    }

    @Test
    public void run_set(){
        redisTemplate.setValueSerializer(new GenericToStringSerializer<String>(String.class));
        redisTemplate.delete("set");
        redisTemplate.opsForSet().add("set","a");
        redisTemplate.opsForSet().add("set","b");
        redisTemplate.opsForSet().add("set","c");
        redisTemplate.opsForSet().add("set","c");
        redisTemplate.opsForSet().add("set","e");
        System.out.println(redisTemplate.opsForSet().size("set"));
        redisTemplate.opsForSet().add("set1","a");
        redisTemplate.opsForSet().add("set1","b");
        redisTemplate.opsForSet().add("set1","c");
        redisTemplate.opsForSet().add("set1","d");
        redisTemplate.opsForSet().add("set1","f");
        /*redisTemplate.opsForSet().difference("set","set1").forEach(x->{
            System.out.println(x);
        });
        redisTemplate.opsForSet().intersect("set","set1").forEach(x->{
            System.out.println(x);
        });*/
        redisTemplate.opsForSet().members("set").forEach(x -> System.out.println(x));
        System.out.println(redisTemplate.opsForSet().randomMember("set"));

        try(Cursor cursor = redisTemplate.opsForSet().scan("set1", ScanOptions.scanOptions().build())){
            while (cursor.hasNext()){
                System.out.println(cursor.next());
            }
        }catch (Exception e){}
    }

    @Test
    public void run_hash(){
        redisTemplate.delete("hash");
        redisTemplate.opsForHash().put("hash","age",16);
        redisTemplate.opsForHash().put("hash","name","zhangsan");
        redisTemplate.opsForHash().put("hash","grade",5);
        int age = (int) redisTemplate.opsForHash().get("hash", "age");
        System.out.println(age);
        Boolean hasGrade = redisTemplate.opsForHash().hasKey("hash", "grade");
        System.out.println(hasGrade);
        Set keys = redisTemplate.opsForHash().keys("hash");
        System.out.println(keys);

        Cursor<Map.Entry<Object, Object>> curosr = redisTemplate.opsForHash().scan("hash", ScanOptions.NONE);
        while(curosr.hasNext()){
            Map.Entry<Object, Object> entry = curosr.next();
            System.out.println(entry.getKey()+":"+entry.getValue());
        }
    }

    @Test
    public void run_zset(){
        redisTemplate.delete("zset");
        redisTemplate.opsForZSet().add("zset","a",1);
        redisTemplate.opsForZSet().add("zset",'b',2.0);
        redisTemplate.opsForZSet().add("zset",'c',3.0);
        redisTemplate.opsForZSet().add("zset",'d',4.0);
        Set zset = redisTemplate.opsForZSet().range("zset", 0, -1);
        System.out.println(zset);
        Long drank = redisTemplate.opsForZSet().rank("zset", "a");
        System.out.println(drank);
    }

    @Test
    public void run_string(){
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // 设置value的序列化规则和 key的序列化规则
//        redisTemplate.setKeySerializer(jackson2JsonRedisSerializer);
//        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();
        redisTemplate.delete("string");
        redisTemplate.opsForValue().set("string","abcdefg");
        System.out.println(redisTemplate.opsForValue().get("string"));
        redisTemplate.opsForValue().set("string","mno",3);
        System.out.println(redisTemplate.opsForValue().get("string"));

        redisTemplate.delete("key");
        redisTemplate.opsForValue().set("key","hello world");
        System.out.println(redisTemplate.opsForValue().get("key"));
        redisTemplate.opsForValue().set("key","redis", 6);
        //这里注意使用StringRedisSerializer
        System.out.println(redisTemplate.opsForValue().get("key"));
        //
    }

    @Test
    public void run_hyperlog(){
        redisTemplate.delete("hyper");
        redisTemplate.opsForHyperLogLog().add("hyper","ab");
        redisTemplate.opsForHyperLogLog().add("hyper","cd");
        redisTemplate.opsForHyperLogLog().add("hyper","cd");
        redisTemplate.opsForHyperLogLog().add("hyper","cd");
        redisTemplate.opsForHyperLogLog().add("hyper","ef");
        redisTemplate.opsForHyperLogLog().add("hyper","ef");
        System.out.println(redisTemplate.opsForHyperLogLog().size("hyper"));
//        redisTemplate.opsForHyperLogLog().delete("hyper");
//        System.out.println(redisTemplate.opsForHyperLogLog().size("hyper"));

        redisTemplate.opsForHyperLogLog().add("hyper2","ab");
        redisTemplate.opsForHyperLogLog().add("hyper2","cd");
        redisTemplate.opsForHyperLogLog().add("hyper2","cd");
        redisTemplate.opsForHyperLogLog().add("hyper2","cd");
        redisTemplate.opsForHyperLogLog().add("hyper2","ef");
        redisTemplate.opsForHyperLogLog().add("hyper2","ef");
        redisTemplate.opsForHyperLogLog().add("hyper2","gh");

        redisTemplate.opsForHyperLogLog().union("hyper3","hyper","hyper2");
        System.out.println(redisTemplate.opsForHyperLogLog().size("hyper3"));
        System.out.println(redisTemplate.opsForHyperLogLog().size("hyper","hyper2","hyper3"));
        //求一个大集合的基数个数，Distinct Value，简称dv，不保证准确率，只需12k的大小
        //12*1024*8
        //计算某个接口被多少个不同的ip访问过
        //统计某个主播被多少个不同的人点赞过

    }

    /*
    实战，实现一个bloom过滤器
     */
    @Test
    public void run_bloom(){

    }
    @Test
    public void run_bit(){
        //redisTemplate.getConnectionFactory().getConnection().setBit();
    }

    @Test
    public void run_sub_pub(){
    }
}
